package com.umpay.utils;

import java.nio.ByteBuffer;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.umpay.dict.XmlData;
import com.umpay.dict.retcode.MerBusiEC;
import com.umpay.exception.BusinessException;


/**
 * @功能说明 用密钥进行3DES加密，解密的相关方法
 */
public class DES3Util {
	public static final Logger log = LogManager.getLogger(DES3Util.class);
	private static final int DES_SAND = 0x12345678;
	private static final String digits = "0123456789abcdef";
	
	/**
	 * 与接入通信3DES加密
	 * 对传入的字符串进行3DES加密，并返回加密结果
	 * @param info String 需要加密的字符串
	 * @return 加密后的字符串 String
	 */
	public static String encrypt3DES(String info, String desKey) throws Exception {
		if (null == info || "".equals(info)) {
			return "";
		}
		try {
			byte[] key = desKey.getBytes();
//			byte[] encryptInfo = cipher(padding(info.getBytes("UTF-8")), key, Cipher.ENCRYPT_MODE, "DESede/ECB/NoPadding");
			byte[] encryptInfo = cipher(info.getBytes("UTF-8"), key, Cipher.ENCRYPT_MODE, "DESede");
			return byte2HexString(encryptInfo);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
	}
	
	/**
	 * 与接入通信3DES解密
	 * 对传入的字符串进行3DES解密，并返回解密结果
	 * @param info String 需要解密的字符串
	 * @return 解密后的字符串 String
	 */
	public static String decrypt3DES(String info, String desKey) throws Exception {
		if (null == info || "".equals(info)) {
			return "";
		}
		try{
			byte[] key = desKey.getBytes();
			byte[] decryptInfo = cipher(hexStr2Byte(info), key, Cipher.DECRYPT_MODE, "DESede");
			return new String(decryptInfo,"UTF-8");	
//			return new String(unpadding(decryptInfo),"UTF-8");	
		}catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}

	}
	
	public static String encrypt(String srcMsg,String desKey){
		String desStr = null;
		try {
			byte[] srcByteGbk = srcMsg.getBytes("UTF-8");
			byte[] destMsg = encTDes(srcByteGbk,desKey.getBytes());
			desStr = byte2HexString(destMsg);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return desStr;
	}
	
	public static String decrypt(String desStr, String desKey) throws Exception {
		if (null == desStr || "".equals(desStr)) {
			return "";
		}
		try{
			byte[] key = desKey.getBytes();
			byte[] decryptInfo = decTDes(hexStr2Byte(desStr), key);
			return new String(decryptInfo,"UTF-8");
		}catch (Exception e) {
			throw e;
		}
	}
	
	public static byte[] encTDes(byte binfo[],byte[] bDesKey) throws Exception {
		return cipher(binfo, bDesKey, Cipher.ENCRYPT_MODE, "DES/ECB/PKCS5Padding");
	}
	
	public static byte[] decTDes(byte binfo[], byte bDesKey[]) throws Exception {
		return cipher(binfo, bDesKey, Cipher.DECRYPT_MODE, "DES/ECB/PKCS5Padding");
	}
	
	/**
	 * 确保8的倍数
	 * @param src
	 * @return
	 */
	private static byte[] padding(byte[] src) {
		byte[] pad;
		int mod = src.length % 8;
		if (mod == 0) {
			pad = new byte[4 + 4 + src.length];
		} else {
			pad = new byte[4 + 4 + src.length + 8 - mod];
		}
		int2net(DES_SAND, pad, 0);
		int2net(src.length, pad, 4);
		System.arraycopy(src, 0, pad, 8, src.length);
		return pad;
	}
	
	/**
	 * padding的反操作
	 * @param buf
	 * @return
	 */
	private static byte[] unpadding(byte[] buf) {
		int sand = net2int(buf, 0);
		if (sand != DES_SAND)
			return null;
		int len = net2int(buf, 4);
		byte[] unpad = new byte[len];
		System.arraycopy(buf, 8, unpad, 0, unpad.length);
		return unpad;
	}
	
	/**
	 *  整数->网络序 
	 */
	private static void int2net(int i, byte[] buf4, int offset) {
		buf4[offset + 0] = (byte) (i >>> 24 & 0xff); // 网络顺序
		buf4[offset + 1] = (byte) (i >>> 16 & 0xff);
		buf4[offset + 2] = (byte) (i >>> 8 & 0xff);
		buf4[offset + 3] = (byte) (i & 0xff);
	}

	/**
	 *  网络序->整数 
	 */
	private static int net2int(byte[] buf, int offset) {
		int i = (buf[offset + 0] & 0xff) << 24 | (buf[offset + 1] & 0xff) << 16
				| (buf[offset + 2] & 0xff) << 8 | (buf[offset + 3] & 0xff); // 网络顺序
		return i;
	}

	/**
	 * DES加/解密方法
	 */
	public static byte[] cipher(byte info[], byte bDesKey[], int mode, String transformation) throws Exception {
		String algs[] = transformation.split("/");
		SecretKey key = new SecretKeySpec(bDesKey, algs[0]);
		Cipher c1 = Cipher.getInstance(transformation);
		c1.init(mode, key);
		return c1.doFinal(info);
	}

	/**
	 * 将byte数组转为16进制字符串
	 */
	private static String byte2HexString(byte[] data) {
		StringBuffer buf = new StringBuffer();
		for (int i = 0; i != data.length; i++) {
			int v = data[i] & 0xff;
			buf.append(digits.charAt(v >> 4));
			buf.append(digits.charAt(v & 0xf));
		}
		return buf.toString().toUpperCase();
	}
	
	/**
	 * 将16进制字符串转为byte数组
	 */
	public static byte[] hexStr2Byte(String hex){
		System.out.println(hex.length());
		ByteBuffer bf = ByteBuffer.allocate(hex.length()/2);
		for(int i=0;i<hex.length();i++){
			String hexStr=hex.charAt(i)+"";
			i++;
			hexStr+=hex.charAt(i);
			byte b = (byte)Integer.parseInt(hexStr,16);
			bf.put(b);
		}
		return bf.array();
	}
	 /**
     * 内部应用之间敏感字段3DES加密
     * @param data  要加密的数据
     * @return 加密后的字符串，使用base64进行编码
     * @throws Exception
     */
    public static String appEncrypt(String data){
    	PropertyUtil  propertyUtil = (PropertyUtil)SpringUtil.getBean("propertyUtil");
    	String key = propertyUtil.getProperty(XmlData.APP_3DES_KEY);
    	if(StringUtils.isEmpty(key)){
    		throw new BusinessException(MerBusiEC.RESULT_UNKNOW,"未配置内部应用3DES加密key");
    	}
    	String value = null;
    	try {
    		value = encrypt3DES(data, key);
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(MerBusiEC.RESULT_UNKNOW,"内部应用3DES加密失败");
		}
    	return value;
    }
    /**
     * 内部应用敏感字段3DES解密
     * @param data
     * @return
     * @throws Exception
     */
    public static String appDecrypt(String data){
    	PropertyUtil  propertyUtil = (PropertyUtil)SpringUtil.getBean("propertyUtil");
    	String key = propertyUtil.getProperty(XmlData.APP_3DES_KEY);
    	if(StringUtils.isEmpty(key)){
    		throw new BusinessException(MerBusiEC.RESULT_UNKNOW,"未配置merbusi应用3DES加密key");
    	}
    	String value = null;
    	try {
    		value = decrypt3DES(data, key);
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(MerBusiEC.RESULT_UNKNOW,"内部应用应用3DES解密失败");
		}
    	return value;
    } 
	public static void main(String args[]) {
		try {
			String str1 = encrypt3DES("测试用户","RfjNLMcZoKzbaTCsYvbnbPLr");
			String str2 = decrypt3DES("AE6C4A296F0C089D185CCB615F8E08258AAF229A2CDA7FDB8FC3C11DE52FAC7DDA32E671E5C93972CB601B2A055CB84F903552275E934FFB1F0793BF7426FF2AA81A4282F4571E6C5660F46EF73B345949AAEBE3361EDC2241C5E04FEC47F92BB2C0FEB7A331C05B4ABB3C07E5CDF9CE162BA9ED3278B683689F39F38593DA26C761475086CEA13351E6ED1228E536B521EB9DD80510E2A4693ACCDA73746F138DF90A8CAF1B1ECC2D6D2EED0D4B86DA","RfjNLMcZoKzbaTCsYvbnbPLr");
			System.out.println(str1);
			System.out.println(str2);
			System.out.println("$$"+appDecrypt("295DDA019A977E0376B45F196400E246247B7815EF286439"));
//			String str1 = encrypt("汉字","x8ey319670pg615biffjb4nd");
//			String str2 = decrypt("19CFFD15823338629275614EBE08006F78B1795E14DD3855E18117A64FDFC2BD5DB17146C147F877E1E44E153E895954A9FDE1AB80E6E1910B13421D4D05816ADBAC647EF8484069444144B3F6B8FBF1313AB4CFC0AD178BDA8B92246F65B2F7B13FA5A729BF9AE9E121A0CC743FF705F15F250042BF4172C3BAAE80069D0ECE","x8ey319670pg615biffjb4nd");
////			System.out.println(str1);
//			System.out.println(str2);
			
			
			//System.out.println(new String(hexStr2Byte("BACEC6E4"),"UTF-8"));
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
